/**
  * @file	W25Q64.c
  *	@author	yoyoyes
  * @date	2023-6-7
  */

#include "spi.h"
#include "W25Q64.h"  
  
/**
  * @func	gd_hal_spi0_init
  * @param	none
  * @return	none
  */
void W25Q64_init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);
	gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
	
	CS_DISENABLE;
	gd_hal_spi_init();
}

/**
  * @func	W25Q64_wait_busy
  * @param	none
  * @return	none
  */
void W25Q64_wait_busy(void)
{
	uint8_t res;
	
	do{
		CS_ENABLE;
		spi_read_write_byte(SPI0, 0x05);				/* 读状态寄存器S7 - S0 */
		res = spi_read_write_byte(SPI0, 0xff);
		CS_DISENABLE;
	}while((res & 0x01) == 0x01);						/* 等待空闲 */
}

/**
  * @func	W25Q64_enable
  * @param	none
  * @return	none
  */
void W25Q64_enable(void)
{
	W25Q64_wait_busy();
	CS_ENABLE;
	spi_read_write_byte(SPI0, 0x06);					/* 写使能 */
	CS_DISENABLE;
}

/**
  * @func	W25Q64_block_erase
  * @param	block		块
  * @return	none
  */
void W25Q64_block_erase(uint8_t block)
{
	uint8_t data[4];
	
	data[0] = 0xD8;										/* 选择块擦除 */
	data[1] = (block * 64 * 1024) >> 16;
	data[1] = (block * 64 * 1024) >> 8;
	data[1] = block * 64 * 1024;
	
	W25Q64_wait_busy();
	W25Q64_enable();
	CS_ENABLE;
	spi_write_data(SPI0, data, 4);
	CS_DISENABLE;
	W25Q64_wait_busy();
}

/**
  * @func	W25Q64_page_write
  * @param	buf		数据指针
  * @param	page	页
  * @return	none
  */
void W25Q64_page_write(uint8_t *buf, uint16_t page)
{
	uint8_t data[4];
	
	data[0] = 0x02;								/* 写数据 */
	data[1] = (page * 256) >> 16;
	data[2] = (page * 256) >> 8;
	data[3] = page * 256;
	
	W25Q64_wait_busy();
	W25Q64_enable();
	CS_ENABLE;
	spi_write_data(SPI0, data, 4);
	spi_write_data(SPI0, buf, 256);
	CS_DISENABLE;
	W25Q64_wait_busy();
}

/**
  * @func	W25Q64_data_read
  * @param	buf		数据指针
  * @param	addr	读地址
  * @param	len		长度
  * @return	none
  */
void W25Q64_data_read(uint8_t *buf, uint32_t addr, uint32_t len)
{
	uint8_t data[4];
	
	data[0] = 0x03;								/* 读数据 */
	data[1] = addr >> 16;
	data[2] = addr >> 8;
	data[3] = addr;
	
	W25Q64_wait_busy();
	CS_ENABLE;
	spi_write_data(SPI0, data, 4);
	spi_read_data(SPI0, buf, len);
	CS_DISENABLE;
}
